
/**
 * 在 file_cat 基础上增加标准输出、标准输入的重定向
 * + 等于 > 输出重定向
 * - 等于 < 输入重定向
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

#define BUFF_SIZE 4096

void copy(int in_fd, int out_fd)
{
    int len;
    char buff[BUFF_SIZE];
    while (1)
    {
        len = read(in_fd, buff, BUFF_SIZE);

        if (len <= 0)
        {
            if (EINTR == errno)
            {
                continue;
            }
            // fprintf(stderr, "Read file error!\n");
            break;
        }

        write(out_fd, buff, len);
    }
}

int main(int argc, char **argv)
{

    int i = 1;
    int in_fd, out_fd;
    int flag = 0;

    for (; i < argc; ++i)
    {
        flag = 1;
        if (!strcmp(argv[i], "+"))
        {
            if ((out_fd = open(argv[++i], O_WRONLY | O_CREAT, 0666)) < 0)
            {
                perror("Open out_fd error:");
                exit(EXIT_FAILURE);
            }

            if (dup2(out_fd, STDOUT_FILENO) < 0)
            {
                perror("dup2 error:");
                exit(EXIT_FAILURE);
            }

            close(out_fd);
        }
        else if (!strcmp(argv[i], "-"))
        {
            if ((in_fd = open(argv[++i], O_RDONLY)) < 0)
            {
                perror("Open in_fd error:");
                exit(EXIT_FAILURE);
            }

            if (dup2(in_fd, STDIN_FILENO) < 0)
            {
                perror("dup2 error:");
                exit(EXIT_FAILURE);
            }

            close(in_fd);
        }
        else
        {
            if ((in_fd = open(argv[i], O_RDONLY)) < 0)
            {
                perror("Open in_fd error:");
                exit(EXIT_FAILURE);
            }

            if (dup2(in_fd, STDIN_FILENO) < 0)
            {
                perror("dup2 error:");
                exit(EXIT_FAILURE);
            }

            close(in_fd);
        }

        copy(STDIN_FILENO, STDOUT_FILENO);
    }

    if (!flag)
    {
        copy(STDIN_FILENO, STDOUT_FILENO);
    }
    return 0;
}